import requests
import json
import urllib3
import tushare as ts
import pandas as pd
import time
import numpy as np
import socket
import sys
import getopt


# for InsecureRequestWarning
urllib3.disable_warnings()

socket.setdefaulttimeout(30)

# -------------------------------------------------

df = None

debug_level_lists = ['release', 'warning', 'debug']

# -------------------------------------------------


class Strategy:
    # 手续费
    cost_sold = 0.0013
    cost_buy = 0.0003

    def __init__(self, fake_unique_id, today_return_all, today2=None, yesterday2=None,debug_level=False):
        # test
        self.debug_level = debug_level

        # 持仓、交易、卖出
        # 其中周六日不算，如果工作日内某天没有交易，那就是空[]。
        self.positions_lists = []
        self.transactions_lists = []
        self.slod_transactions_lists = []

        self.owner = fake_unique_id[0:9]
        self.unique_id = fake_unique_id[10:]

        # 今日收益：总 = 买 + 卖
        self.today_return_all = today_return_all
        self.today_return_buy = -1
        # 卖出的今日收益 = 成交额/成交量/昨日收盘*（1-手续费卖）*仓位
        self.today_return_sold = -1

        # 四个指标
        self.today_closing_price_sold = -1
        self.yesterday_closing_price_sold = -1
        self.today_closing_price_buy = -1           # 今收 = 当日市值 / 成交额
        # 今开 = 今收*（1-0.0003）/[今日收益/仓位 + 1]
        self.today_openning_price_buy = -1

        # 仓位
        self.hold_percent_ratio_sold = 0
        self.hold_percent_ratio_buy = 0

        # 买卖情况circumstance
        self.circumstance_buy = ''
        self.circumstance_sold = ''

        # 日期
        # 今日
        if today2 == None:
            self.today2 = time.strftime("%Y-%m-%d", time.localtime())
            self.isToday = True
        # 历史
        else:
            self.today2 = today2
            self.isToday = False
            
        # 昨天
        if yesterday2 == None:
            t0_struct = time.strptime(self.today2, "%Y-%m-%d")
            t0_second = time.mktime(t0_struct)
            t0_weekday = time.strftime("%w", t0_struct)

            # 一天的秒数
            one_day = 86400

            day_num = 1
            if t0_weekday == '1':
                day_num = 3
            
            t1_second = t0_second - one_day * day_num
            t1_struct = time.localtime(t1_second)
            self.yesterday = time.strftime('%Y-%m-%d', t1_struct)
        # 历史
        else:
            self.yesterday = yesterday2
            
        

    def tackle_lists_content(self):
        # 持仓详情
        url_positions_lists = 'https://bigquant.com/bigwebapi/algo_info/position?owner=' + \
            self.owner+'&notebook_id=' + self.unique_id + '&limit=-1'
        # url_positions_lists = 'https://bigquant.com/bigwebapi/algo_info/position?owner=yilong_10&notebook_id=1a9be36e-6de4-11ea-bc2b-0a580a830103&limit=-1'

        # 交易详情
        url_transactions_lists = 'https://bigquant.com/bigwebapi/algo_info/transaction?owner=' + \
            self.owner+'&notebook_id=' + self.unique_id + '&limit=-1'
        # url_transactions_lists = 'https://bigquant.com/bigwebapi/algo_info/transaction?owner=yilong_10&notebook_id=1a9be36e-6de4-11ea-bc2b-0a580a830103&limit=-1'

        # 卖出详情
        url_slod_transactions_lists = 'https://bigquant.com/bigwebapi/algo_info/sold_transaction?owner=' + \
            self.owner+'&notebook_id=' + self.unique_id + '&limit=-1'
        # url_slod_transactions_lists = 'https://bigquant.com/bigwebapi/algo_info/sold_transaction?owner=yilong_10&notebook_id=1a9be36e-6de4-11ea-bc2b-0a580a830103&limit=-1'

        # 获取json对象
        positions_lists_response_json = get_response_json(url_positions_lists)
        transactions_lists_response_json = get_response_json(
            url_transactions_lists)
        slod_transactions_lists_response_json = get_response_json(
            url_slod_transactions_lists)

        # 获取列表
        self.positions_lists = positions_lists_response_json['data']['positions_lists']
        self.transactions_lists = transactions_lists_response_json['data']['transactions_lists']
        self.slod_transactions_lists = slod_transactions_lists_response_json[
            'data']['slod_transactions_lists']

    def tackle_today_return_sold(self):

        # 在卖出详情中找到某天的情况
        index = 0
        # 股票代码
        code_sid = None    # 防止没找超出下标和为空的两种情况，且用于提供股票代码
        length = len(self.slod_transactions_lists)
        while index < length:
            if len(self.slod_transactions_lists[index]) > 0:
                if self.slod_transactions_lists[index][0]['date'] == self.today2:
                    code_sid = self.slod_transactions_lists[index][0]['sid']
                    break
            index += 1

        # 没卖自然是0
        if code_sid == None:
            self.today_return_sold = 0
            self.circumstance_sold = '[无卖]'
            if self.debug_level == debug_level_lists[1] or self.debug_level == debug_level_lists[2]:
                print('[没有卖的..............]')
        else:
            self.circumstance_sold = '[有卖]'
            if self.debug_level == debug_level_lists[1] or self.debug_level == debug_level_lists[2]:
                print('[有卖的股票]: %s.......' % (code_sid,))

            # 找仓位占比------------------------------------------------------------
            # 在持仓详情中找到某天的情况
            index_2 = 0
            length = len(self.positions_lists)
            while index < length:
                if len(self.positions_lists[index]) > 0:
                    if self.positions_lists[index][0]['date'] == self.yesterday and self.positions_lists[index][0]['hold_days'] == 1:
                        self.hold_percent_ratio_sold = self.positions_lists[
                            index][0]['hold_percent_ratio']
                        break
                index += 1

            # 如果没有找到仓位
            if self.hold_percent_ratio_sold == 0:
                raise Exception(
                    "hold_percent_ratio_sold can't find.......................")

            # 找今日和昨收------------------------------------------------------------
            url_code_sid = 'https://bigquant.com/bigwebapi/stock/fetch_stock_kline?instrument=' + code_sid
            # url_1 = 'https://bigquant.com/bigwebapi/stock/fetch_stock_kline?instrument=601969.SHA'
            response_code_sid = get_response_json(url_code_sid)
            day_lists = response_code_sid['data']['stock_info']['ohlc']['day']
            # 要倒着来
            while len(day_lists) > 0:
                each_10086 = day_lists.pop()
                t_10086 = float(each_10086['x'])/1000
                t_str_10086 = time.strftime(
                    '%Y-%m-%d', time.localtime(t_10086))
                if t_str_10086 == self.today2:
                    self.today_closing_price_sold = each_10086['close']
                    self.yesterday_closing_price_sold = each_10086['pre_close']
                    break

            # 计算
            self.today_return_sold = (self.today_closing_price_sold/self.yesterday_closing_price_sold*(
                1-self.cost_sold)-1)*self.hold_percent_ratio_sold
            if self.debug_level == debug_level_lists[2]:
                print('\n[today_return_sold]: ( %3f / %3f * (1 - %3f) - 1) * %3f = %3f' %
                      (self.today_closing_price_sold, self.yesterday_closing_price_sold,
                       self.cost_sold, self.hold_percent_ratio_sold, self.today_return_sold)
                      )
        pass

    # 计算今收（现价）

    def isBuy_today_return_buy(self):

        # 在持仓详情中找到某天的情况
        index = 0
        flag = False    # 防止没找超出下标和为空的两种情况
        length = len(self.positions_lists)
        while index < length:
            if len(self.positions_lists[index]) > 0:
                if self.positions_lists[index][0]['date'] == self.today2:
                    flag = True
                    break
            index += 1

        # 没有买的
        if flag == False:
            self.circumstance_buy = '[无买]'
            if self.debug_level == debug_level_lists[1] or self.debug_level == debug_level_lists[2]:
                print('[连买的都没有..............]')
            return False
        else:
            self.circumstance_buy = '[有买]'
            if self.debug_level == debug_level_lists[1] or self.debug_level == debug_level_lists[2]:
                print('[有买的股票..............]')

            # 今日收益（买）的计算部分 = 总 - 卖
            self.today_return_buy = self.today_return_all - self.today_return_sold
            if self.debug_level == debug_level_lists[2]:
                print('\n[today_return_buy] = %3f - %3f = %3f' %
                      (self.today_return_all, self.today_return_sold, self.today_return_buy))

            # 当日市值
            value = self.positions_lists[index][0]['value']
            # 成交量
            amount = self.positions_lists[index][0]['amount']
            # 仓位占比
            self.hold_percent_ratio_buy = self.positions_lists[index][0]['hold_percent_ratio']

            self.today_closing_price_buy = value/amount
            if self.debug_level == debug_level_lists[2]:
                print('\n[today_closing_price_buy]: %3f / %3f = %3f' %
                      (value, amount, self.today_closing_price_buy))

            self.today_openning_price_buy = self.today_closing_price_buy * \
                (1-self.cost_buy)/(self.today_return_buy /
                                   self.hold_percent_ratio_buy+1)
            if self.debug_level == debug_level_lists[2]:
                print('\n[today_openning_price_buy]:  %3f * (1-%3f) / (%3f/%3f+1) = %3f\n' %
                      (self.today_closing_price_buy, self.cost_buy, self.today_return_buy, self.hold_percent_ratio_buy, self.today_openning_price_buy))
            print('[现价]=%3f,[开盘]=%3f' %
                  (self.today_closing_price_buy, self.today_openning_price_buy))
            return True
        pass

    # 结果处理
    def get_code_lists(self):

        self.tackle_lists_content()

        self.tackle_today_return_sold()

        # 今天没有买股票，那就可以跳过这个策略了
        if self.isBuy_today_return_buy() == False:
            return None
        # 只处理买了股票的
        else:
            code_lists = []

            diff = 0.005
            # 因为tushare的数据有时候很粗糙（比如1.2写成1，从而有0.1的误差），所以设定逐次增加。
            while len(code_lists) == 0 and diff < 1.0:
                a, b = None, None
                if self.isToday == True:
                    # trade对应today_closing_price今收，对应today_openning_price今开
                    a = df[((df['trade'] - self.today_closing_price_buy) > -diff) &
                           ((df['trade'] - self.today_closing_price_buy) < diff) &
                           ((df['open'] - self.today_openning_price_buy) > -diff) &
                           ((df['open'] - self.today_openning_price_buy) < diff)]
                    b = np.array(a['code'])
                else:
                    # close对应today_closing_price今收，对应today_openning_price今开
                    a = df[((df['close'] - self.today_closing_price_buy) > -diff) &
                           ((df['close'] - self.today_closing_price_buy) < diff) &
                           ((df['open'] - self.today_openning_price_buy) > -diff) &
                           ((df['open'] - self.today_openning_price_buy) < diff)]
                    b = np.array(a['ts_code'])

                code_lists = list(b)
                diff += 0.01
            return code_lists

    def print_positions_lists(self):
        print('----------------------------')
        for i in self.positions_lists:
            if len(i) > 0:
                print(i[0]['date'], i[0]['value'], i[0]['hold_percent_ratio'])
        print('----------------------------')


# -------------------------------------------------

def get_response_json(url):
    headers1 = {
        'Host': 'bigquant.com',
        'Connection': 'keep-alive',
        'Accept': 'application/json, text/plain, */*',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
    }
    response = requests.get(url=url, headers=headers1, verify=False)

    # 解析json
    response_json = json.loads(response.text)
    return response_json


# 策略的排名
def get_share_algo_lists(owner='yilong_10'):
    share_algo_lists = []

    # 查寻作者id
    url_share_algo_lists = 'https://bigquant.com/bigwebapi/algo_list/share?page=1&limit=10&order_by=-grade&search='+owner
    # url_share_algo_lists = 'https://bigquant.com/bigwebapi/algo_list/share?page=1&limit=10&order_by=-grade&search=yilong_10'
    # print(url_share_algo_lists)

    response_json = get_response_json(url_share_algo_lists)

    share_algo_lists = response_json['data']['share_algo_lists']

    return share_algo_lists


# ----------------------------test function----------------------------
# 打印综合排序的名字顺序


def print_share_algo_lists_algo_name(share_algo_lists):
    print('----------------------------')
    for i in share_algo_lists:
        print(i['algo_name'])
    print('----------------------------')


def main():

    today_setting, yesterday_setting ,today_return, owner, id, debug_level, notWrite = None, None, None, None, None, 'release', False
    try:
        opts, args = getopt.getopt(sys.argv[1:], "t:y:r:o:i:d:n",
                                   ["today2=", "yesterday2","return=", "owner=", "id=", "debug=", "notWrite"])

        # 就是处理每个元组
        for k, v in opts:
            if k in ("-t", "--today2"):
                today_setting = v
            elif k in ("-y", "--yesterday2"):
                yesterday_setting = v
            elif k in ("-r", "--return"):
                today_return = v
            elif k in ("-o", "--owner"):
                owner = v
            elif k in ("-i", "--id"):
                id = v
            elif k in ("-d", "--debug"):
                debug_level = v
            elif k in ("-n", "--notWrite"):
                notWrite = True
    except getopt.GetoptError:
        raise getopt.GetoptError
        print(
            '---------------------- [getopt.GetoptError] ----------------------')
        sys.exit()

    count_setting = -1
    owner_lists = None

    # 运行release
    if debug_level == debug_level_lists[0]:
        count_setting = 3
        # owner_lists = ['yilong_10']
        owner_lists = ['yilong_10', 'yilong_20', 'yilong_30',
                       'yilong_40', 'yilong_50', 'yilong_60']
    # 测试1warning
    elif debug_level == debug_level_lists[1]:
        count_setting = 3
        owner_lists = ['yilong_40']
    # 测试2debug
    elif debug_level == debug_level_lists[2]:
        count_setting = 100
        owner_lists = ['yilong_10', 'yilong_20', 'yilong_30',
                       'yilong_40', 'yilong_50']

    # ------------------------------------------------------------------------------------------------------
    # 写入新数据（注意：会有访问强度限制）
    global df
    if notWrite == False:
        # 查询历史记录
        if today_setting != None:
            ts.set_token(
                'fe53a8928a5442e82ec2ed835f02562c7f5ac24fe7edaa2a40299c8a')
            pro = ts.pro_api()
            today_st = today_setting.replace('-', '')
            df = pro.daily(trade_date=today_st)
            df.sort_values(by=['close', 'pre_close'], ascending=False).to_csv(
                r'./BigWork/src/today2.csv')
        else:
            df = ts.get_today_all()
            df.sort_values(by=['trade', 'open'], ascending=False).to_csv(
                r'./BigWork/src/today2.csv')
    # 不写入
    else:
        df = pd.read_csv(r'./BigWork/src/today2.csv', encoding='utf-8')
    print('\ncsv loaded............................\n')
    # ------------------------------------------------------------------------------------------------------
    # record：查看还有谁没买也没卖
    record_lists = []
    for i in range(20):
        record_lists.append(list())
        for j in range(12):
            record_lists[i].append('')

    # 写入到result.csv中
    all_code_lists = []

    # 最新
    if today_setting == None:
        for i, owner in enumerate(owner_lists):
            print('----------------------------%s----------------------------' % (owner,))
            share_algo_lists = get_share_algo_lists(owner)
            record_lists[0][2*i] = owner

            # 表示选择符合规定的前3个
            count = 0
            for j, share_algo in enumerate(share_algo_lists):
                print('[策略名字]: %s\n' % (share_algo['algo_name'],))
                record_lists[j+1][2*i] = share_algo['algo_name']

                myStrategy = None
                if yesterday_setting == None:
                    myStrategy = Strategy(
                        share_algo['unique_id'], share_algo['today_return'], debug_level=debug_level)
                else:
                    myStrategy = Strategy(
                        share_algo['unique_id'], share_algo['today_return'], debug_level=debug_level, yesterday2=yesterday_setting)

                code_lists = myStrategy.get_code_lists()
                print(code_lists, '\n\n')

                circumstance = myStrategy.circumstance_buy + myStrategy.circumstance_sold
                if circumstance == '[无买][无卖]':
                    circumstance = '★★'
                if myStrategy.circumstance_buy == '[有买]':
                    circumstance = '√' + circumstance
                record_lists[j+1][2 * i + 1] = circumstance

                # 只统计买了股票的策略
                if code_lists != None:
                    count += 1
                    if len(code_lists) == 1:
                        all_code_lists.append(code_lists[0])
                    else:
                        all_code_lists.append(code_lists)
                    if count == count_setting:
                        break

        # 写入记录record
        record_df = pd.DataFrame(
            np.array(record_lists, dtype=object))
        record_df.to_csv(r'./BigWork/src/record.csv')
        print('已写入记录record............')

        # 写入结果
        print('一一对应，可以去result.csv中复制了............')
        result_df = pd.DataFrame(np.array(all_code_lists, dtype=object).reshape(1, -1))
        result_df.to_csv(r'./BigWork/src/result.csv')
    # 查询历史
    else:
        share_algo_lists = get_share_algo_lists(owner)
        for share_algo in share_algo_lists:
            if str(share_algo['id']) == id:
                print('[策略名字]: %s\n' % (share_algo['algo_name'],))
                myStrategy = Strategy(
                    share_algo['unique_id'], today_return, debug_level=debug_level, today2=today_setting)
                code_lists = myStrategy.get_code_lists()
                print(code_lists, '\n\n')
                break


if __name__ == '__main__':
    main()
